Friend MustInherit Class cAbstractReader

    Protected pNumberOfRows As Integer
    Protected pNumberOfColumns As Integer
    Protected pDoesHaveBooleanNumericLastColumn As Boolean
    Protected pDoesHaveNumericFirstColumn As Boolean
    Protected pEstimatedNumberOfTaxonomicColumns As Integer
    Protected pEstimatedNumberOfRightAlignedNumericColumns As Integer
    Protected pErrorTextWhenEvaluatingCells As String


    Public Sub New()
        ' nothing here
    End Sub


    Protected Sub InferMoreMetaInfoFromData()

        Dim ColumnIndex As Integer

        ' last column is boolean 0/1
        If GetStringValue(2, pNumberOfColumns) = "0" OrElse GetStringValue(2, pNumberOfColumns) = "1" Then
            pDoesHaveBooleanNumericLastColumn = True
        End If

        ' first column is numeric
        If Not ReadOptionalDoubleValue(2, 1) Is Nothing Then
            pDoesHaveNumericFirstColumn = True
            ColumnIndex = 2
        Else
            pDoesHaveNumericFirstColumn = False
            ColumnIndex = 1
        End If

        For ColumnIndex = ColumnIndex To pNumberOfColumns
            If IsCellValueNumericNonEmpty(IndexOfFirstDataRow, ColumnIndex) Then
                pEstimatedNumberOfTaxonomicColumns = ColumnIndex - 1
                If pDoesHaveNumericFirstColumn Then
                    pEstimatedNumberOfTaxonomicColumns = pEstimatedNumberOfTaxonomicColumns - 1
                End If
                pEstimatedNumberOfRightAlignedNumericColumns = pNumberOfColumns - ColumnIndex + 1
                Exit For
            End If
        Next

    End Sub

    Public ReadOnly Property DoesHaveNumericFirstColumn() As Boolean
        Get
            Return pDoesHaveNumericFirstColumn
        End Get
    End Property

    Public ReadOnly Property DoesHaveBooleanNumericLastColumn() As Boolean
        Get
            Return pDoesHaveBooleanNumericLastColumn
        End Get
    End Property

    Public ReadOnly Property NumericFirstColumnValue(ByVal RowIndex As Integer) As Integer
        Get
            Dim NumericValue As Integer

            If pDoesHaveNumericFirstColumn Then
                Try
                    NumericValue = CType(GetStringValue(RowIndex, 1), Integer)
                Catch Exception As Exception
                    NumericValue = Integer.MinValue ' no value defined, return flag
                End Try
            Else
                NumericValue = Integer.MinValue ' no value defined, return flag
            End If

            Return NumericValue

        End Get
    End Property


    Public ReadOnly Property EstimatedNumberOfTaxonomicColumns() As Integer
        Get
            Return pEstimatedNumberOfTaxonomicColumns
        End Get
    End Property

    Public ReadOnly Property EstimatedNumberOfRightAlignedNumericColumns() As Integer
        Get
            Return pEstimatedNumberOfRightAlignedNumericColumns
        End Get
    End Property

    Public Sub AddErrorToErrorText(ByVal Text As String)

        pErrorTextWhenEvaluatingCells = pErrorTextWhenEvaluatingCells & vbLf & Text

    End Sub

    Public ReadOnly Property ErrorTextWhenEvaluatingCells() As String
        Get
            Return pErrorTextWhenEvaluatingCells
        End Get
    End Property

    Public ReadOnly Property NumberOfRows() As Integer
        Get
            Return pNumberOfRows
        End Get
    End Property

    Public ReadOnly Property NumberOfColumns() As Integer
        Get
            Return pNumberOfColumns
        End Get
    End Property

    Public MustOverride Function GetStringValue(ByVal RowIndexBaseOne As Integer, ByVal ColumnIndexBaseOne As Integer) As String

    Private Function IsCellValueNumericNonEmpty(ByVal RowIndexBaseOne As Integer, ByVal ColumnIndexBaseOne As Integer) As Boolean

        Dim StringValue As String
        Dim Result As Boolean

        StringValue = GetStringValue(RowIndexBaseOne, ColumnIndexBaseOne)
        StringValue = StringValue.Trim()

        Result = False
        If IsNumeric(StringValue) Then
            Result = True
        Else
            StringValue = StringValue.Replace(",", ".")
            If IsNumeric(StringValue) Then
                Result = True
            Else
                StringValue = StringValue.Replace(".", ",")
                Result = IsNumeric(StringValue)
            End If
        End If

        Return Result

    End Function

    Public Function ReadDoubleValue(ByVal RowIndexBaseOne As Integer, ByVal ColumnIndexBaseOne As Integer) As Double

        Dim StringValue As String
        Dim DoubleValue As Double

        StringValue = GetStringValue(RowIndexBaseOne, ColumnIndexBaseOne)
        StringValue = StringValue.Trim()
        If Len(StringValue) > 0 Then
            StringValue = StringValue.Replace(",", ".")
            DoubleValue = Val(StringValue)
        Else
            Throw New Exception("Expected numeric value was not found in data file")
        End If

        Return DoubleValue

    End Function

    Public Function ReadOptionalDoubleValue(ByVal RowIndexBaseOne As Integer, ByVal ColumnIndexBaseOne As Integer) As Double?

        Dim StringValue As String
        Dim DoubleValue As Double?

        StringValue = GetStringValue(RowIndexBaseOne, ColumnIndexBaseOne)
        StringValue = StringValue.Trim()
        If Len(StringValue) > 0 Then
            StringValue = StringValue.Replace(",", ".")
            DoubleValue = Val(StringValue)
        End If

        Return DoubleValue

    End Function


End Class
